package com.cxx.purchasecharge.component.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.cxx.purchasecharge.component.bean.ActionResult;
import com.cxx.purchasecharge.component.bean.ActionResult.ActionResultStatus;
import com.cxx.purchasecharge.component.bean.DataGridRequestForm;
import com.cxx.purchasecharge.component.bean.GenericPagingResult;
import com.cxx.purchasecharge.component.bean.LoginUser;
import com.cxx.purchasecharge.component.bean.OrderBean;
import com.cxx.purchasecharge.component.bean.OrderItemBean;
import com.cxx.purchasecharge.component.bean.PCApplicationContext;
import com.cxx.purchasecharge.component.bean.SearchRequestForm;
import com.cxx.purchasecharge.component.exception.ApplicationException;
import com.cxx.purchasecharge.component.utils.AjaxUtils;
import com.cxx.purchasecharge.component.utils.BeanConvertUtils;
import com.cxx.purchasecharge.component.utils.ComponentConstants;
import com.cxx.purchasecharge.component.utils.MessageProperties;
import com.cxx.purchasecharge.core.model.OrderSearchForm;
import com.cxx.purchasecharge.core.model.OrderStatusCode;
import com.cxx.purchasecharge.core.model.OrderTypeCode;
import com.cxx.purchasecharge.core.model.persistence.Order;
import com.cxx.purchasecharge.core.model.persistence.OrderItem;
import com.cxx.purchasecharge.core.model.persistence.Payment;
import com.cxx.purchasecharge.dal.common.IDGenerator;
import com.cxx.purchasecharge.service.CoreService;
import com.cxx.purchasecharge.service.QueryService;

@Controller
@RequestMapping ("/inOrder")
public class InOrderManager extends GenericController <OrderBean>
{
    private static final Logger logger = Logger.getLogger (InOrderManager.class);

    @Autowired
    private CoreService coreService;
    @Autowired
    private QueryService queryService;

    @Autowired
    private PCApplicationContext pcContext;

    public InOrderManager ()
    {
        super.setViewName("inOrderManagement");
    }

    @Override
    public String getModelBySearchForm(
        DataGridRequestForm dataGridRequestForm,
        SearchRequestForm searchRequestForm,
        HttpServletRequest request)
    {
        logger.debug (dataGridRequestForm);
        int page = dataGridRequestForm.getPage () - 1;
        int size = dataGridRequestForm.getRows ();
        String sortField = parseSortField (dataGridRequestForm.getSort ());
        String order = dataGridRequestForm.getOrder ();
        Pageable pageable = new PageRequest (page, size, new Sort ("asc".equalsIgnoreCase (order) ? Direction.ASC
                                                                                                 : Direction.DESC,
                                                                   sortField));
        
        LoginUser loginUser = null;
        String type = "";
        try
        {
            loginUser = pcContext.getLoginUser (request);
            type = validateOrderType (request);
        }
        catch (Exception e)
        {
            logger.warn(e.getMessage(), e);
        }
        
        if (null != loginUser)
        {
            OrderTypeCode typeCode = OrderTypeCode.IN.toString ().equals (type) ? OrderTypeCode.IN
                                                                               : OrderTypeCode.IN_RETURN;
            OrderSearchForm searchForm = BeanConvertUtils.searchRequestForm2OrderSearchForm (searchRequestForm);
            Page <Order> orderPage = null;
            List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
            if (null != searchForm && searchForm.getOrderId () != 0)
            {
                Order ord = queryService.findOrderById (searchForm.getOrderId ());
                List <Order> list = new ArrayList <Order> ();
                orderPage = new PageImpl <Order> (list, pageable, 0);
                if (null != ord)
                {
                    list.add (ord);
                    orderPage = new PageImpl <Order> (list, pageable, 1);
                }
                footer = countTotalForOrders (orderPage.getContent ());
            }
            else
            {
                orderPage = queryService.findOrderBySearchForm (typeCode, pageable, searchForm, loginUser.getUserId (),
                                                                loginUser.isAdmin ());
                float sumReceivable = queryService.countOrderReceivableBySearchForm (typeCode, searchForm,
                                                                                     loginUser.getUserId (),
                                                                                     loginUser.isAdmin ());
                float sumProfit = queryService.countOrderProfitBySearchForm (typeCode, searchForm,
                                                                             loginUser.getUserId (),
                                                                             loginUser.isAdmin ());
                Map <String, String> map = new HashMap <String, String> ();
                map.put ("id", "合计");
                map.put (ComponentConstants.RECEIVABLE_MONEY, sumReceivable + "");
                map.put (ComponentConstants.PROFIT_MONEY, sumProfit + "");
                footer.add (map);
            }
            long total = orderPage.getTotalElements ();
            GenericPagingResult <OrderBean> orderPagingResult = new GenericPagingResult <OrderBean> ();
            orderPagingResult.setRows (BeanConvertUtils.orderList2OrderBeanList (orderPage.getContent ()));
            orderPagingResult.setTotal (total);
            orderPagingResult.setFooter (footer);

            JSONObject jsonObject = JSONObject.fromObject (orderPagingResult);
            return jsonObject.toString ();
        }
        return "";
    }

    @Override
    public String getModelById(@RequestParam String orderId, HttpServletRequest request)
    {
        if (StringUtils.isNotBlank (orderId))
        {
            Order order = new Order ();
            order.setId (Long.parseLong (orderId));
            List <OrderItem> orderItems = queryService.findOrderItemByOrder (order);
            if (!CollectionUtils.isEmpty (orderItems))
            {
                GenericPagingResult <OrderItemBean> orderPagingResult = new GenericPagingResult <OrderItemBean> ();
                orderPagingResult.setRows (BeanConvertUtils.orderItemList2OrderItemBeanList (orderItems));
                orderPagingResult.setTotal (orderItems.size ());
                orderPagingResult.setFooter (countTotalForOrderItems (orderItems));

                JSONObject jsonObject = JSONObject.fromObject (orderPagingResult);
                return jsonObject.toString ();
            }
        }
        return "";
    }

    @Override
    public String addModel(@Valid OrderBean bean, BindingResult bindingResult, HttpServletRequest request)
    {
        if (bindingResult.hasErrors ())
        {
            logger.error (bindingResult.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                bean.setOrderItemBeans (parseOrderItem (bean));
                Order order = BeanConvertUtils.orderBean2Order (bean);
                order.setId (IDGenerator.getIdentityID ());
                coreService.saveOrder (order);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_SUCCESS,
                                                                                     ComponentConstants.MSG_IN_ORDER))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_FAIL,
                                                                                     ComponentConstants.MSG_IN_ORDER))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
    }

    @Override
    public String updateModel(@Valid OrderBean bean, BindingResult bindingResult, HttpServletRequest request)
    {
        if (bindingResult.hasErrors ())
        {
            logger.error (bindingResult.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                coreService.updateOrderStatus (Long.parseLong (bean.getId ()), bean.getStatusCode (),
                    bean.getComment ());
                ar = ActionResult.ok ()
                    .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                        ComponentConstants.MSG_IN_ORDER_STATUS))
                        .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                    .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_FAIL,
                        ComponentConstants.MSG_IN_ORDER_STATUS))
                        .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
        
        /*if (bindingResult.hasErrors ())
        {
            logger.error (bindingResult.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                Order order = BeanConvertUtils.orderBean2Order (bean);
                coreService.saveOrder (order);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_IN_ORDER))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_FAIL,
                                                                                     ComponentConstants.MSG_IN_ORDER))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }*/
    }

    @Override
    public String deleteModels(@RequestParam String ids, HttpServletRequest request)
    {
        if (null != ids && ids.trim ().length () > 0)
        {
            List <Order> orders = new ArrayList <Order> ();
            Order order;
            if (ids.indexOf (";") != -1)
            {
                String[] idArr = ids.split (";");
                for (String typeId : idArr)
                {
                    order = new Order ();
                    order.setId (Long.parseLong (typeId));
                    orders.add (order);
                }
            }
            else
            {
                order = new Order ();
                order.setId (Long.parseLong (ids));
                orders.add (order);
            }

            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                coreService.deleteOrders (orders);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_IN_ORDER))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_FAIL,
                                                                                     ComponentConstants.MSG_IN_ORDER))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            logger.error (ActionResultStatus.BAD_REQUEST.toString ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
    }

    private String validateOrderType (HttpServletRequest request) throws ApplicationException
    {
        String type = request.getParameter ("type");
        if (StringUtils.isBlank (type))
        {
            throw new ApplicationException ("Order type code is empty.");
        }
        if (!OrderTypeCode.IN.toString ().equals (type) && !OrderTypeCode.IN_RETURN.toString ().equals (type))
        {
            throw new ApplicationException (
                                            "Order type code '"
                                                    + type
                                                    + "' is not supported, accepted type code is OrderTypeCode.IN or OrderTypeCode.IN_RETURN");
        }
        return type;
    }

    private List <Map <String, String>> countTotalForOrderItems (List <OrderItem> orderItemList)
    {
        List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
        if (!CollectionUtils.isEmpty (orderItemList))
        {
            Map <String, String> map = new HashMap <String, String> ();
            int amountTotal = 0;
            float sumTotal = 0;
            for (OrderItem ordItem : orderItemList)
            {
                amountTotal += ordItem.getAmount ();
                sumTotal += ordItem.getSum ();
            }
            map.put (ComponentConstants.ORDER_UNIT_PRICE, "合计");
            map.put (ComponentConstants.ORDER_AMOUNT, amountTotal + "");
            map.put (ComponentConstants.ORDER_SUM, sumTotal + "");
            footer.add (map);
        }
        return footer;
    }

    @SuppressWarnings ("unused")
    private List <Map <String, Object>> countOrderPaid (float dealMoney, List <Payment> payments)
    {
        List <Map <String, Object>> footer = new ArrayList <Map <String, Object>> ();
        if (!CollectionUtils.isEmpty (payments))
        {
            Map <String, Object> map = new HashMap <String, Object> ();
            float countOrderPaid = 0;
            String paidResult = "";
            for (Payment op : payments)
            {
                countOrderPaid += op.getPaid ();
            }
            if (dealMoney == countOrderPaid)
            {
                paidResult = "回款完成";
            }
            else if (dealMoney > countOrderPaid)
            {
                paidResult = "欠" + (dealMoney - countOrderPaid);
            }
            map.put (ComponentConstants.PAY_DATE, "状态");
            map.put (ComponentConstants.PAID, paidResult);
            footer.add (map);
        }
        else
        {
            Map <String, Object> map = new HashMap <String, Object> ();
            map.put (ComponentConstants.PAY_DATE, "状态");
            map.put (ComponentConstants.PAID, "尚无回款");
            footer.add (map);
        }
        return footer;
    }

    private List <Map <String, String>> countTotalForOrders (List <Order> orderList)
    {
        List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
        if (!CollectionUtils.isEmpty (orderList))
        {
            Map <String, String> map = new HashMap <String, String> ();
            float dealMoneyTotal = 0;
            float receivableMoneyTotal = 0;
            // float paidMoneyTotal = 0;
            float profitMoneyTotal = 0;
            for (Order ord : orderList)
            {
                if (ord.getStatusCode () == OrderStatusCode.FINISHED || ord.getStatusCode () == OrderStatusCode.NEW)
                {
                    dealMoneyTotal += ord.getDealMoney ();
                    receivableMoneyTotal += ord.getReceivable ();
                    // paidMoneyTotal += ord.getPaidMoney ();
                    profitMoneyTotal += ord.getProfit ();
                }
            }
            // footer.put (ComponentConstants.CUSTOMER_NAME, "当页合计");
            map.put ("id", "合计");
            map.put (ComponentConstants.DEAL_MONEY, dealMoneyTotal + "");
            map.put (ComponentConstants.RECEIVABLE_MONEY, receivableMoneyTotal + "");
            // footer.put (ComponentConstants.PAID_MONEY, paidMoneyTotal + "");
            map.put (ComponentConstants.PROFIT_MONEY, profitMoneyTotal + "");
            footer.add (map);
        }
        return footer;
    }

    private String parseSortField (final String sortField)
    {
        String sortFieldAfterParse = ComponentConstants.CUSTOMER_DOT_SHORT_NAME;
        if (!StringUtils.isBlank (sortField))
        {
            sortFieldAfterParse = sortField;
            if (ComponentConstants.CUSTOMER_NAME.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.CUSTOMER_DOT_SHORT_NAME;
            }
            else if (ComponentConstants.PAY_TIME.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.PAY_DATE;
            }
            else if (ComponentConstants.CREATE_TIME.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.CREATE_DATE;
            }
        }
        return sortFieldAfterParse;
    }

    private List <OrderItemBean> parseOrderItem (OrderBean orderBean)
    {
        List <OrderItemBean> orderItemBeans = new ArrayList <OrderItemBean> ();
        String orderItemListStr = orderBean.getOrderItemList ();
        if (StringUtils.isNotBlank (orderItemListStr))
        {
            String[] orderItemArr = orderItemListStr.split (";");
            if (orderItemArr.length > 0)
            {
                for (String orderItem : orderItemArr)
                {
                    if (StringUtils.isNotBlank (orderItem))
                    {
                        String[] itemArr = orderItem.split (",");
                        OrderItemBean orderItemBean = new OrderItemBean ();
                        orderItemBean.setId (itemArr[0]);
                        orderItemBean.setGoodsId (itemArr[1]);
                        orderItemBean.setGoodsUnit (itemArr[2]);
                        orderItemBean.setUnitPrice (StringUtils.isNotBlank (itemArr[3]) ? Float.parseFloat (itemArr[3])
                                                                                       : 0);
                        orderItemBean.setAmount (StringUtils.isNotBlank (itemArr[4]) ? Integer.parseInt (itemArr[4])
                                                                                    : 0);
                        orderItemBean.setSum (StringUtils.isNotBlank (itemArr[6]) ? Float.parseFloat (itemArr[6]) : 0);
                        orderItemBean.setComment (itemArr[5]);
                        orderItemBean.setImportPrice (StringUtils.isNotBlank (itemArr[7]) ? Float.parseFloat (itemArr[7])
                                                                                         : 0);
                        orderItemBeans.add (orderItemBean);
                    }
                }
            }
        }
        return orderItemBeans;
    }

}
